<?php
/*
   Copyright (c) [2020] [liyunde]
   [open-client-phpsdk] is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2.
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
   See the Mulan PSL v2 for more details.
 */

namespace LIYunde\Cloud\Api\Request;

use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use LIYunde\Cloud\Api\Common\OpenApiConfig;
use LIYunde\Cloud\Api\Common\RequestForm;
use LIYunde\Cloud\Api\Common\SdkErrors;
use Monolog\Logger;
use SplFileObject;

/**
 * Class OpenRequest
 * @author liyunde
 * @since 2020/8/23
 *
 * @package LIYunde\Cloud\Api\Request
 */
class OpenRequest {

    /**
     * @var OpenApiConfig
     */
    private $openConfig;

    /**
     * @var \Monolog\Logger $logger
     */
    private $logger;

    /**
     * @var Client
     */
    private $client;

    private $userAgent;

    /**
     * OpenRequest constructor.
     * @param OpenApiConfig $openConfig
     * @param null | \Monolog\Logger $logger
     */
    public function __construct(OpenApiConfig $openConfig, $logger = null) {
        $this->openConfig = $openConfig;

        $this->client = new Client();

        $this->logger = $logger;

        $this->userAgent = $openConfig->getUserAgent() . $this->client->getConfig('headers')['User-Agent'];
    }

    /**
     * @param \Monolog\Logger $logger
     */
    public function setLogger($logger) {
        $this->logger = $logger;
    }

    /**
     * @param string $url
     * @param RequestForm $requestForm
     * @param array $header
     * @return string
     * @since 2019/9/19 17:27
     * @author liyunde
     */
    public function request($url, $requestForm, array $header = null) {

        $files = $requestForm->getFiles();

        if ($files != null && count($files) > 0) {
            return $this->uploadFile($url, $requestForm);
        }

        $form = $requestForm->getForm();

        if (gettype($form[$this->openConfig->getDataName()]) != 'string')
            $form[$this->openConfig->getDataName()] = json_encode($form[$this->openConfig->getDataName()], JSON_UNESCAPED_UNICODE);

        $val = [];

        foreach ($form as $k => $v) {
            $val[] = "$k=" . urlencode($v);
        }

        $data = [
            'verify' => false,
            'headers' => [
                'User-Agent' => $this->userAgent,
                'Content-type' => 'application/x-www-form-urlencoded'
            ],
            'body' => implode('&', $val)
        ];

        return $this->sendHttpRequest($url, $data);
    }

    /**
     * @param $url
     * @param array $data
     * @return false|string
     * @since 2020/8/23 11:26
     * @author liyunde
     */
    private function sendHttpRequest($url, array $data) {

        try {

            if (empty($data)) throw new \InvalidArgumentException("请求数据不能为空");

            if ($this->logger && $this->logger->isHandling(Logger::DEBUG)) {
                $this->logger->debug("开始请求:$url", $data);
            }

            $res = $this->client->post($url, $data);

            if ($this->logger && $this->logger->isHandling(Logger::DEBUG)) {
                $this->logger->debug("执行请求返回:{$res->getReasonPhrase()}({$res->getStatusCode()})", $res->getHeaders());
            }

            if ($res && $res->getStatusCode() == 200) {
                if ($this->logger) {
                    $this->logger->info("响应 content-type:", $res->getHeader('Content-Type'));
                }

                return $res->getBody()->getContents();
            }

            $result = (new SdkErrors($res->getStatusCode(), $res->getBody()))->getErrorResponse();
        } catch (\InvalidArgumentException $e) {
            if ($this->logger) {
                $this->logger->error("请求参数解析出错了:{$e->getMessage()}", $e->getTrace());
            }
            $result[$this->openConfig->getErrorResponseName()] = SdkErrors::InvalidArgumentError($e->getMessage());
        } catch (GuzzleException $e) {
            if ($this->logger) {
                $this->logger->error("调用平台接口出错了:{$e->getMessage()}", $e->getTrace());
            }
            $result[$this->openConfig->getErrorResponseName()] = (new SdkErrors($e->getCode(), $e->getMessage()))->getErrorResponse();
        } catch (Exception $e) {
            if ($this->logger) {
                $this->logger->error("系统出错了:{$e->getMessage()}", $e->getTrace());
            }
            $result[$this->openConfig->getErrorResponseName()] = (new SdkErrors($e->getCode(), $e->getMessage()))->getErrorResponse();
        }

        return json_encode($result, JSON_UNESCAPED_UNICODE);
    }


    public function uploadFile($url, $requestForm) {

        $files = $requestForm->getFiles();

        if ($files != null && count($files) > 0) {

            $fileData = [];

            /**
             * @var SplFileObject $file
             */
            foreach ($files as $file) {
                $fileData[] = [
                    'name' => $file->getBasename(),
                    'filename' => $file->getFilename(),
                    'contents' => $file,
                ];
            }

            $data = [
                'verify' => false,
                'headers' => [
                    'User-Agent' => $this->userAgent
                ],
                'multipart' => $fileData
            ];

            return $this->sendHttpRequest($url, $data);
        }

        $result[$this->openConfig->getErrorResponseName()] = SdkErrors::InvalidArgumentError("要上传的文件为空,请设置");

        return json_encode($result, JSON_UNESCAPED_UNICODE);
    }
}
